﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Nest;
using Newtonsoft.Json;
using System.Diagnostics;
using System.Net;
using System.Reflection;
using UAParser;

namespace Magic.Core;

public class ActionFilter : IAsyncActionFilter
{
    private readonly IConfiguration _configuration;

    public ActionFilter(IConfiguration configuration)
    {
        this._configuration = configuration;
    }

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var actionContext = await AuditLog(context, next);

        //var actionContext = await next();

        object data = actionContext.Result switch
        {
            ContentResult contentResult => contentResult.Content,
            ObjectResult objectResult => objectResult.Value,
            EmptyResult => null,
            _ => null
        };

        if (IsNonUnify(context))
        {
            actionContext.Result = new JsonResult(IsEncryptResponse(context) ? data.EncryptCBC(context.HttpContext) : data);
        }
        else
        {
            actionContext.Result = new JsonResult(new RestfulResult<object>
            {
                Code = 1,
                Success = true,
                Data = IsEncryptResponse(context) ? data.EncryptCBC(context.HttpContext) : data,
                Msg = "请求成功",
                Timestamp = DateTime.Now.Millisecond
            });
        }
    }

    private bool IsEncryptResponse(ActionExecutingContext context)
    {
        var enableGlobalResponseEncrypt = _configuration.GetSection("WebSetting:EnableGlobalResponseEncrypt").Value.ParseToBool();

        bool enableEncrypt = enableGlobalResponseEncrypt;

        var encryptResponseAttribute = GetAttribute<UnEncryptResponseAttribute>(context);

        if (encryptResponseAttribute != null)
        {
            enableEncrypt = encryptResponseAttribute.EnableEncrypt;
        }
        return enableEncrypt;
    }

    private bool IsNonUnify(ActionExecutingContext context)
    {
        bool nonUnify = false;

        var attribute = GetAttribute<NonUnifyAttribute>(context);

        nonUnify = !attribute.IsNull();

        return nonUnify;
    }

    private T GetAttribute<T>(ActionExecutingContext context) where T : Attribute
    {
        var endpoint = context.HttpContext.GetEndpoint();
        if (endpoint?.Metadata?.GetMetadata<T>() is T attribute)
        {
            return attribute;
        }
        return null;
    }


    private async Task<ActionExecutedContext> AuditLog(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var httpContext = context.HttpContext;
        var httpRequest = httpContext.Request;
        var sw = Stopwatch.StartNew();

        var actionContext = await next();

        var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
        sw.Stop();
        //判断是否请求成功（没有异常就是请求成功）
        var isRequestSucceed = actionContext.Exception == null;
        var headers = httpRequest.Headers;
        var clientInfo = headers.ContainsKey("User-Agent") ? Parser.GetDefault().Parse(headers["User-Agent"]) : null;
        var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
        var ip = HttpUtil.GetRemoteIp();

        var log = new AuditLog
        {
            Parameters = JsonConvert.SerializeObject(context.ActionArguments.Count < 1 ? "" : context.ActionArguments),
            BrowserInfo = JsonConvert.SerializeObject(clientInfo),
            ClientName = "",
            ClientIpAddress = ip,
            ExecutionDuration = sw.ElapsedMilliseconds,
            ExecutionTime = now,
            ReturnValue = "",
            Exception = isRequestSucceed ? "" : actionContext.Exception.StackTrace,
            MethodName = actionDescriptor?.ActionName,
            ServiceName = context.Controller.ToString(),
            UserInfo = UserManager.UserId.ToString(),
            CustomData = ""
        };
        Console.WriteLine(JsonConvert.SerializeObject(log));
        return actionContext;
    }
}

public class AuditLog
{
    /// <summary>
    /// 调用参数
    /// </summary>
    public string Parameters { get; set; }
    /// <summary>
    /// 浏览器信息
    /// </summary>
    public string BrowserInfo { get; set; }
    /// <summary>
    /// 客户端信息
    /// </summary>
    public string ClientName { get; set; }
    /// <summary>
    /// 客户端IP地址
    /// </summary>
    public string ClientIpAddress { get; set; }
    /// <summary>
    /// 执行耗时
    /// </summary>
    public long ExecutionDuration { get; set; }
    /// <summary>
    /// 执行时间
    /// </summary>
    public long ExecutionTime { get; set; }
    /// <summary>
    /// 返回内容
    /// </summary>
    public string ReturnValue { get; set; }
    /// <summary>
    /// 异常对象
    /// </summary>
    public string Exception { get; set; }
    /// <summary>
    /// 方法名
    /// </summary>
    public string MethodName { get; set; }
    /// <summary>
    /// 服务名
    /// </summary>
    public string ServiceName { get; set; }
    /// <summary>
    /// 调用者信息
    /// </summary>
    public string UserInfo { get; set; }
    /// <summary>
    /// 自定义数据
    /// </summary>
    public string CustomData { get; set; }
}





